
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<linux/ioctl.h>
#include<string.h>
#include <unistd.h>    // 提供 write, read, close 的声明

#include "wdt.h"

#define MAX_TIMEOUT 255 
#define DEFAULT_TIMEOUT 250
#define WATCHDOG_DEV "/dev/ft_wdt"

static const char helpMsg[] =
    "Usage: \n"
    "        start      start watchdog, default set 250 seconds\n"
    "   feed time       feed hard watchdog, max set 255 seconds\n"
    "        status     show hard watchdog status\n"
    "        stop       stop hard watchdog\n"
    "";


// 函数用于检查ft_wdt驱动是否加载，返回1表示加载，返回0表示未加载
static int check_driver_loaded() {
    FILE *fp;
    char buffer[128];

    fp = popen("lsmod | grep -w ft_wdt", "r");
    if (fp == NULL) {
        perror("popen failed");
        return 0;
    }

    if (fgets(buffer, sizeof(buffer), fp)!= NULL) {
        // 如果读取到了内容，说明找到了匹配的驱动，返回1表示已加载
        pclose(fp);
        return 1;
    }

    pclose(fp);
    return 0;
}

int wdt_load_driver()
{
    if (check_driver_loaded() == 0) {
        int iRet = system("insmod /lib/modules/5.4.18-53-generic/ft_wdt.ko");
        if (iRet != 0) {
            return -1;
        }
    }
    return 0;
}

int wdt_unload_driver()
{
    if (check_driver_loaded() == 1) {
        int iRet = system("rmmod ft_wdt");
        if (iRet != 0) {
            return -1;
        }
    }
    return 0;
}

int wdt_start()
{
    int fd, ret;

    // 打开文件句柄
    fd = open(WATCHDOG_DEV, O_RDWR);
    if (fd < 0) {
        printf("open %s failure\n", WATCHDOG_DEV);
        return -2;
    }

    // 开启硬件狗
    ret = write(fd, "start", strlen("start"));
    if (ret == -1) {
        printf("Watchdog start err %d.\n", ret);
        close(fd);
        return ret;
    }

    close(fd);
    return 0;
}

int wdt_stop()
{
    int fd, ret = 0;

    fd = open(WATCHDOG_DEV, O_RDWR);
    if (fd < 0) {
        printf("open %s failure\n", WATCHDOG_DEV);
        return -2;
    }

    // 关闭硬件狗
    ret = write(fd, "stop", strlen("stop"));
    if (ret == -1) {
        printf("Watchdog stop err %d.\n", ret);
        close(fd);
        return ret;
    }

    close(fd);
    return 0;
}

int wdt_status()
{
    int fd;
    int buffer[10];

    fd = open(WATCHDOG_DEV, O_RDWR);
    if (fd < 0) {
        printf("open %s failure\n", WATCHDOG_DEV);
        return -2;
    }

    memset(buffer, 0, sizeof(buffer));
    read(fd, buffer, 1);

    close(fd);
    return buffer[0];
}

int wdt_feed(int time, int unit)
{
    int fd, ret;
    char feed_second[10];

    // 入参校验
    if (time <= 0 || time > MAX_TIMEOUT || unit != TIME_UNIT_SECONDS) {
        printf("param [%d-%d] invalid\n", time, unit);
        return -1;
    }

    // 打开文件句柄
    fd = open(WATCHDOG_DEV, O_WRONLY);
    if (fd < 0) {
        printf("open %s failure\n", WATCHDOG_DEV);
        return -2;
    }

    // 设置硬件狗重启时间
    memset(feed_second, 0, sizeof(feed_second));
    snprintf(feed_second, sizeof(feed_second), "feed %d", time);
    ret = write(fd, feed_second, strlen(feed_second));
    if (ret == -1) {
        printf("Watchdog feed err %d.\n", ret);
        close(fd);
        return ret;
    }

    close(fd);
    return 0;
}

#ifdef __MAIN__

int main(int argc, char **argv)
{
    if (argc < 2) {
        printf("%s", helpMsg);
        return 1;
    }
    wdt_load_driver();

    if (strcmp(argv[1], "start") == 0) {
        if (wdt_start() == 0) {
            printf("watchdog start successful\n");
        } else {
            perror("watchdog start failure\n");
            return 1;
        }
    } else if (strcmp(argv[1], "feed") == 0 && argc == 3) {
        int time = atoi(argv[2]);
        if (time > MAX_WDT_TIME) {
            printf("Maximum time for feeding is %d seconds\n", MAX_WDT_TIME);
            return 1;
        } else {
            if (wdt_feed(time, TIME_UNIT_SECONDS) == 0) {
                printf("watchdog feed successful\n");
            } else {
                perror("watchdog feed failure\n");
                return 1;
            }
        }
    } else if (strcmp(argv[1], "status") == 0) {
        int status = wdt_status();
        if (status == -1) {
            printf("watchdog is disable\n");
        } else {
            printf("watchdog reboot time: [%d]\n", status);
        }
    } else if (strcmp(argv[1], "stop") == 0) {
        if (wdt_stop() == 0) {
            printf("watchdog stop successful\n");
        } else {
            perror("watchdog stop failure\n");
        }
    } else {
        printf("%s\n", helpMsg);
        return 1;
    }

    return 0;
}

#endif
